﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Net;
using System.Threading;
using System.Diagnostics;

namespace QuickTuner
{
    /// <summary>
    /// Provide icon for stations
    /// </summary>
    public static class IconProvider
    {
        public const int DownloadBufferSize = 256 * 1024;        // 256KB buffer

        private static Func<string, Image> getIcon = GetIcon;

        private static Dictionary<string, string> _tempFiles;
        private static Mutex _tempFilesMutex;

        // constructors _______________________________________________________

        static IconProvider()
        {
            _tempFilesMutex = new Mutex(false);
            _tempFiles = new Dictionary<string, string>();
        }

        // methods ____________________________________________________________

        public static Image GetIcon(Station s)
        {
            return GetIcon(s.StationURL);
        }

        public static IAsyncResult BeginGetIcon(Station s, AsyncCallback callback)
        {
            return getIcon.BeginInvoke(s.StationURL, callback, null);
        }

        public static IAsyncResult BeginGetIcon(Station s, AsyncCallback callback, object state)
        {
            return getIcon.BeginInvoke(s.StationURL, callback, state);
        }

        public static Image EndGetIcon(IAsyncResult ar)
        {
            return getIcon.EndInvoke(ar);
        }

        public static string GetIconUrl(string stationUrl)
        {
            var uri = new Uri(stationUrl);
            return "http://{0}/favicon.ico".F(uri.Host);
        }

        // actual download routine, invoked in its own separate thread
        private static Image GetIcon(string url)
        {
            var ms = new MemoryStream();
            Image img = null;

            var iconUrl = GetIconUrl(url);


            // check if we have already downloaded the file
            // load from the saved temp file, if it is so
            try {
                _tempFilesMutex.WaitOne();
                if (_tempFiles.ContainsKey(iconUrl))
                    img = Image.FromFile(_tempFiles[iconUrl]);

            } catch {
                // loading failed, proceed to normal downloading
                img = null;

            } finally {
                _tempFilesMutex.ReleaseMutex();

            }

            if (img != null) return img;

            // prepare download
            var wr = WebRequest.CreateDefault(new Uri(iconUrl));
            WebResponse response;
            Stream stream = null;

            try {
                response = wr.GetResponse();
                stream = response.GetResponseStream();

                // download and save in memory
                var bytesRead = 0;
                var buffer = new byte[DownloadBufferSize];

                while ((bytesRead = stream.Read(buffer, 0, DownloadBufferSize)) > 0) {
                    ms.Write(buffer, 0, bytesRead);
                }

                // release the buffer immediatly
                buffer = null;

                // close the response stream to free network connections
                // parsing is done offline afterward
                stream.Close();
                stream.Dispose();


            } catch (WebException ex) {

                // image not found
                if (ex.Message.Contains("404")) return null;

            } finally {

                if (stream != null) {
                    stream.Close();
                    stream.Dispose();
                }

            }

            try {
                // try parsing as Icon first
                ms.Seek(0, SeekOrigin.Begin);
                img = new Icon(ms).ToBitmap();

            } catch {
                try {
                    // if fail, try GDI+ generic Image
                    ms.Seek(0, SeekOrigin.Begin);
                    img = Image.FromStream(ms);

                } catch {
                    // fail
                    img = null;
                }
            }

            if (img != null) {

                var tempPath = Path.GetTempFileName();
                tempPath = Path.ChangeExtension(tempPath, Path.GetExtension(iconUrl));

                // save the downloaded image for quick reference later
                _tempFilesMutex.WaitOne();
                _tempFiles[iconUrl] = tempPath;
                _tempFilesMutex.ReleaseMutex();

                img.Save(tempPath);

            }

            return img;
        }

    }
}
